#include <vector>
#include <iostream>
#include <map>
#include "framework/BasicChecker.h"
#include "DetectMe/Expression.h"
using namespace clang;
using namespace std;
struct configinfo
{
  string container;
  string func;
  unsigned param;
  configinfo(string c, string f, int p)
  {
    container = c;
    func = f;
    param = p;
  }
};
using func_map = map <string,int>;
class UnInitVarChecker : public BasicChecker
{
public:
  UnInitVarChecker(ASTResource *resource, ASTManager *manager,
                   CallGraph *call_graph, Config *configure) : BasicChecker(resource, manager, call_graph, configure) {}
  void check();
  vector<FunctionDecl *> getAllFuncs(string fileName);
  vector<MemberExpr *> getUseMemexpr(vector<MemberExpr *> allexpr, vector<MemberExpr *> cutexpr);
  void readConfig();
  Expr *getBase(MemberExpr *member_expr);
  void ReportBug(FunctionDecl *FD,const SourceLocation SL ,string exprname,string filename,string desc);
  MemberExpr *getMemberExprByFieldDecl(FieldDecl *field_decl,string filename,FunctionDecl *FD);
  vector<Expr *> selectExpr(vector<CallExpr *>);
  func_map ConfigInfos;
  int depth;
};

class FindStructUse : public RecursiveASTVisitor<FindStructUse>
{
public:
  bool VisitMemberExpr(MemberExpr *MemExpr)
  {
    if (MemExpr && MemExpr->getType().getAsString().find("anonymous")==string::npos)
    {
      if (MemExpr->getType().getAsString() != "<bound member function type>" && 
          MemExpr->getType()->getTypeClass()!=clang::Type::ConstantArray) //剔除是成员函数的memberexpr
        allExprs.push_back(MemExpr);
    }
    return true;
  }
  bool VisitCXXMemberCallExpr(CXXMemberCallExpr *containercall_expr);
  bool VisitFunctionType(clang::FunctionType *f){
    is_functionType = true;
    return true;
  }
  vector<MemberExpr *> getAllExprs() { return allExprs; }
  vector<CallExpr *> getcontainer_struct() { return container_struct; }  
  bool is_functionType = false;

private:
  vector<MemberExpr *> allExprs;
  vector<CallExpr *> container_struct;
};

class FindStructUseCut : public RecursiveASTVisitor<FindStructUseCut>
{
  public:
  bool VisitBinaryOperator(BinaryOperator *bOP);
  bool VisitArraySubscriptExpr(ArraySubscriptExpr * Array_expr)
  {
      Expr *lhs = Array_expr->getLHS();
      if(ImplicitCastExpr *imp_tmp = llvm::dyn_cast<ImplicitCastExpr>(lhs)){
        if(MemberExpr *mem_tmp = llvm::dyn_cast<MemberExpr>(imp_tmp->getSubExpr()))
        cutExprs.push_back(mem_tmp);
    }
    return true;
  }
  // bool VisitUnaryOperator(UnaryOperator * UOP);
  bool VisitCallExpr(CallExpr * call_expr);
  // bool VisitImplicitCastExpr(ImplicitCastExpr * implicit_expr);
  vector<MemberExpr *> getCutExprs() { return cutExprs; }

private:
  vector<MemberExpr *> cutExprs;
};

class FindMemberExpr : public RecursiveASTVisitor<FindMemberExpr>
{
public:
  FindMemberExpr(FieldDecl *fd){fieldDecl = fd;}

  bool VisitMemberExpr(MemberExpr *MemExpr)
  {
    if(MemExpr)
    {
      ValueDecl *value_decl = MemExpr->getMemberDecl();
      if(FieldDecl *field_decl = llvm::dyn_cast<FieldDecl>(value_decl))
      {
        if(fieldDecl == field_decl)
        {
            memberexpr = MemExpr;
        }
      }
    }
    return true;
  }
  MemberExpr * getMemberExpr(){return memberexpr;}
private:
  FieldDecl *fieldDecl;
  MemberExpr *memberexpr =nullptr;
};

